package ldh.im.fxbase.service;

import javafx.concurrent.Task;
import ldh.im.dto.base.OkResp;
import ldh.im.dto.business.base.DataChangeReq;
import ldh.im.dto.business.base.SessionInfoReq;
import ldh.im.dto.business.item.SessionItem;
import ldh.im.dto.enums.DataSubType;
import ldh.im.dto.enums.DataType;
import ldh.im.dto.enums.SessionType;
import ldh.im.fxbase.dao.ImGroupDao;
import ldh.im.fxbase.dao.ImGroupUserDao;
import ldh.im.fxbase.dao.ImSessionDao;
import ldh.im.fxbase.data.pojo.ImGroup;
import ldh.im.fxbase.data.pojo.ImGroupUser;
import ldh.im.fxbase.data.pojo.ImSession;
import ldh.im.fxbase.data.pojo.ImUser;
import ldh.im.fxbase.data.pojo.status.ImSessionStatus;
import ldh.im.fxbase.data.pojo.status.ImSessionType;
import ldh.im.fxbase.exception.ECallBack;
import ldh.im.fxbase.rpc.service.RpcMessageService;
import ldh.im.fxbase.rpc.service.RpcPullMessageService;
import ldh.im.fxbase.util.*;
import ldh.im.util.DateUtil;

import java.sql.SQLException;
import java.time.LocalDateTime;
import java.util.*;

public class ImSessionService {

    private ImSessionDao sessionDao = BeanFactory.getInstance().getBean(ImSessionDao.class);
    private ImGroupDao groupDao = BeanFactory.getInstance().getBean(ImGroupDao.class);

    /**
     * 创建会话
     * @param userId
     * @param group
     * @throws SQLException
     */
    public ImSession createSession(String userId, ImGroup group) throws SQLException {
        ImSession session = sessionDao.getByGroupCodeAndUserId(group.getServerId(), userId);
        if (session != null) {
            throw new RuntimeException(String.format("session has existed. groupCode: %s, userId: %s", group.getServerId(), userId));
        }
        session = ImSession.build(userId, group);
        sessionDao.insertSession(session);
        return session;
    }

    /**
     * 创建会话
     * @param userId
     * @param imUser
     * @throws SQLException
     */
    public ImSession createSession(String userId, ImUser imUser) throws SQLException {
        ImSession session = sessionDao.getByUserId(userId, userId, imUser.getUserId());
        if (session != null) {
            throw new RuntimeException(String.format("session has existed. fromUserId: %s, toUserId: %s", userId, imUser.getUserId()));
        }
        session = ImSession.build(userId, imUser);
        sessionDao.insertSession(session);
        return session;
    }

    /**
     * 批量更新或查询会话同步信息
     * @param userId
     * @param sessionItems
     * @throws SQLException
     */
    public void saveOrUpdates(String userId, List<SessionItem> sessionItems) throws SQLException {
        if (sessionItems.size() < 1) return;

        List<ImSession> insertSessionSet = new ArrayList<>();
        List<ImSession> updateSessionSet = new ArrayList<>();
        for(SessionItem sessionItem : sessionItems) {
            String toUserId = sessionItem.getUserId();
            ImSession imSession = buildImSession(userId, sessionItem);

            ImSession imDbSession = null;
            if (sessionItem.getGroupId() != null) { // 群聊
                ImGroup imGroup = groupDao.getByUserIdAndId(userId, sessionItem.getGroupId());
                imDbSession = sessionDao.getByGroupCodeAndUserId(imGroup.getServerId(), userId);
            } else { // 单聊
                imDbSession = sessionDao.getByUserId(userId, userId, toUserId);
            }
            if (imDbSession == null) {
                insertSessionSet.add(imSession);
            } else {
                imSession.setId(imDbSession.getId());
                imSession.setLatelyMessage(imDbSession.getLatelyMessage());
                imSession.setHotMessageTotal(imDbSession.getHotMessageTotal());
                updateSessionSet.add(imSession);
            }
        }
        sessionDao.batchInserts(insertSessionSet);
        sessionDao.batchUpdates(updateSessionSet);
    }

    /**
     * 是否置顶会话
     * @param imSession
     * @param isTop
     */
    public Task topSession(String userId, ImSession imSession, boolean isTop) {
        ECallBack<Boolean> callBack;
        if (imSession.getGroupCode() != null) { // 群聊
            ImGroup group = imSession.getImGroup();
            ImGroupUser groupUser = group.getGroupUserSet().stream().filter(gu->gu.getUserId().equals(userId)).findFirst().get();
            groupUser.setTop(isTop);
            groupUser.setUpdateTime(new Date());
            imSession.setImGroup(group);

            callBack = ()->{
                ImGroupUserDao imGroupUserDao = BeanFactory.getInstance().getBean(ImGroupUserDao.class);
                imGroupUserDao.update(groupUser);
                return true;
            };


        } else {
            if (imSession.getFromUserId().compareTo(imSession.getToUserId()) >= 0) {
                imSession.setTop(isTop);
            } else {
                imSession.setTop2(isTop);
            }
            callBack = ()->{
                ImSessionDao imSessionDao = BeanFactory.getInstance().getBean(ImSessionDao.class);
                imSessionDao.updateSession(imSession);
                return true;
            };
        }

        Task<Boolean> task = createTask(callBack, imSession, isTop, DataSubType.s_ed_top);
        ThreadPoolUtil.submitTask(task, "会话置顶");

        return task;
    }

    /**
     * 会话是否免打扰
     * @param imSession
     * @param isDisturb
     * @return
     */
    public Task disturbSession(String userId, ImSession imSession, boolean isDisturb) {
        ECallBack<Boolean> callBack;
        if (!imSession.isP2p()) { // 群聊
            ImGroup group = imSession.getImGroup();
            ImGroupUser groupUser = group.getGroupUserSet().stream().filter(gu->gu.getUserId().equals(userId)).findFirst().get();
            groupUser.setDisturb(isDisturb);
            groupUser.setUpdateTime(new Date());
            imSession.setImGroup(group);

            callBack = ()->{
                ImGroupUserDao imGroupUserDao = BeanFactory.getInstance().getBean(ImGroupUserDao.class);
                imGroupUserDao.update(groupUser);
                return true;
            };
        } else {
            if (imSession.getFromUserId().compareTo(imSession.getToUserId())>= 0) {
                imSession.setDisturb(isDisturb);
            } else {
                imSession.setDisturb2(isDisturb);
            }
            imSession.setUpdateTime(new Date());

            callBack = ()->{
                ImSessionDao imSessionDao = BeanFactory.getInstance().getBean(ImSessionDao.class);
                imSessionDao.updateSession(imSession);
                return true;
            };
        }
        Task<Boolean> task = createTask(callBack, imSession, isDisturb, DataSubType.s_ed_disturb);
        ThreadPoolUtil.submitTask(task, "会话免打扰");

        return task;
    }

    public ImSession pullSession(String fromUserId, String toUserId, String groupCode) throws SQLException {
        RpcPullMessageService rpcPullMessageService = RpcUtil.getRpcBootstrap().getRpcConfig().getClientBean(RpcPullMessageService.class);
        SessionInfoReq sessionInfoReq = new SessionInfoReq();
        sessionInfoReq.setFromUserId(fromUserId);
        sessionInfoReq.setToUserId(toUserId);
        sessionInfoReq.setGroupCode(groupCode);
        SessionItem sessionItem = rpcPullMessageService.pullSession(sessionInfoReq);
        ImSession session = buildImSession(fromUserId, sessionItem);
        return session;
    }

    /**
     *  删除会话：包含附件
     * @param sessionId
     */
    public void delete(Long sessionId) throws SQLException {
        ImSession session = sessionDao.getSessionById(sessionId);
        MessageService messageService = BeanFactory.getInstance().getBean(MessageService.class);
        messageService.cleanMessage(session.getCurrentUserId(), sessionId);
        session.setUpdateTime(DateUtil.toDate(LocalDateTime.now().plusDays(-15)));
        sessionDao.updateSession(session);
    }

    private Task<Boolean> createTask(ECallBack<Boolean> callBack, ImSession imSession, boolean value, DataSubType dataSubType) {
        Task<Boolean> task = new Task() {

            @Override
            protected Boolean call() throws Exception {

                DataChangeReq dataChangeReq = new DataChangeReq();
                dataChangeReq.setType(DataType.session);
                dataChangeReq.setSubType(dataSubType);
                if (imSession.isP2p()) {
                    dataChangeReq.setKey(imSession.getToUserId());
                } else {
                    dataChangeReq.setKey(imSession.getGroupCode());
                }

                dataChangeReq.setValue(value + "");

                RpcMessageService rpcMessageService = RpcUtil.getRpcBootstrap().getRpcConfig().getClientBean(RpcMessageService.class);
                OkResp okResp = rpcMessageService.sendDataChange(dataChangeReq);

                callBack.callBack();
                return okResp.isSuccess();
            }
        };
        return task;
    }

    private ImSession buildImSession(String userId, SessionItem sessionItem) throws SQLException {
        String groupCode = sessionItem.getGroupId();
        ImSession imSession = null;
        if (groupCode != null) {
            ImGroup imGroup = ImCacheFactory.getInstance().getImGroup(userId, groupCode);
            if (imGroup == null) {
                throw new RuntimeException(String.format("ImGroup is null, userId {}, groupId {}", userId, sessionItem.getGroupId()));
            }
            imSession = ImSession.build(userId, imGroup);
        } else {
            ImUser imUser = ImCacheFactory.getInstance().getUser(sessionItem.getUserId());
            imSession = ImSession.build(userId, imUser);
        }
        imSession.setWaking(sessionItem.isWaking());
        imSession.setTop(sessionItem.isTop());
        imSession.setDisturb(sessionItem.isDisturb());
        imSession.setWaking2(sessionItem.isWaking2());
        imSession.setTop2(sessionItem.isTop2());
        imSession.setDisturb2(sessionItem.isDisturb2());
        imSession.setSessionType(ImSessionType.valueOf(sessionItem.getType().name()));
        imSession.setStatus(ImSessionStatus.valueOf(sessionItem.getStatus().name()));
        imSession.setServerId(sessionItem.getServerId());
        imSession.setCreateTime(DateUtil.toDate(sessionItem.getUpdateTime()));
        imSession.setUpdateTime(imSession.getCreateTime());

        if (sessionItem.getType() != SessionType.chat) {
            imSession.setName(sessionItem.getName());
        }
        return imSession;
    }

}
